﻿namespace ContosoUniversity.Tests
{
    using System.Linq;
    using ContosoUniversity.DAL;
    using Models;
    using Services.AppServices;
    using NRepository.Core.Events;
    using NRepository.TestKit;
    using NUnit.Framework;
    using NRepository.EntityFramework;
    using System.Data.Entity;
    using NRepository.Core;

    [TestFixture]
    public class ContosoApplicationServiceTests
    {
        public ContosoApplicationServiceTests()
        {
            // Set nrepository entity framework interface extension methods to EFLoggedRepositoryExtensions 
            EntityFrameworkRepositoryExtensions.SetDefaultImplementation(EFLoggedRepositoryExtensions.Instance);
        }

        [Test]
        public void AddInstructorWithCourses()
        {
            var repository = new InMemoryRecordedRepository(
                new Course { CourseID = 1 },
                new Course { CourseID = 2 },
                new Course { CourseID = 3 });

            var contosoService = new ContosoApplicationService(repository);
            contosoService.AddInstructorWithCourses(new Instructor { FirstMidName = "dummy" }, new[] { 1, 3 });

            // Check repository calls
            var queriesEvents = repository.QueryRepository.QueryEvents;

            // there should only be one event
            var queryEvent = (GetEntitiesRepositoryQueryEvent)queriesEvents.Single();
            var filterStrategy = (FindByIdsSpecificationStrategy<Course>)queryEvent.GetAggregateStrategies().Single();
            filterStrategy.Ids.Count().ShouldEqual(2);
            filterStrategy.Ids.ToArray()[0].ShouldEqual(1);
            filterStrategy.Ids.ToArray()[1].ShouldEqual(3);

            // Command events
            var commandEvents = repository.CommandRepository.CommandEvents;
            commandEvents.AddedEvents.Count().ShouldEqual(1);
            commandEvents.SavedEvents.Count().ShouldEqual(1);

            // Check inserted data
            var instructor = repository.GetEntity<Instructor>(p => p.ID == 0);
            instructor.FirstMidName.ShouldEqual("dummy");
            instructor.Courses.Count().ShouldEqual(2);
            instructor.Courses.First().CourseID.ShouldEqual(1);
            instructor.Courses.Last().CourseID.ShouldEqual(3);
        }

        [Test]
        public void AddNewCourse()
        {
            var repository = new InMemoryRecordedRepository();
            var contosoService = new ContosoApplicationService(repository);

            var course = new Course { CourseID = 1 };
            contosoService.AddNewCourse(course);

            repository.GetEntity<Course>(p => p.CourseID == 1);
            repository.CommandRepository.CommandEvents.SavedEvents.Count().ShouldEqual(1);
        }

        [Test]
        public void DeleteCourse()
        {
            var events = new RecordedRepositoryEvents();
            var repository = new InMemoryRepository( events);

            var contosoService = new ContosoApplicationService(repository);
            contosoService.DeleteCourse(1);

            events.SavedEvents.Count().ShouldEqual(1);

            var updates = EFLoggedRepositoryExtensions.Instance.GetUpdates();
            ((Course)updates.Single().Key).CourseID.ShouldEqual(1);
            updates.Single().Value.ShouldEqual(EntityState.Deleted);
        }

        [Test]
        public void ModifyCourse()
        {
            var events = new RecordedRepositoryEvents();
            var repository = new InMemoryRepository(new[] { new Course { Title = "title2" } }, events);
            new ContosoApplicationService(repository).ModifyCourse(new Course{Title = "dummy"});

            events.QueryEvents.Count.ShouldEqual(0);
            events.AddedEvents.Count.ShouldEqual(0);
            events.DeletedEvents.Count.ShouldEqual(0);
            events.ModifiedEvents.Count.ShouldEqual(1);
            events.SavedEvents.Count.ShouldEqual(1);

            ((Course)events.ModifiedEvents.Single().Entity).Title.ShouldEqual("dummy");
        }
    }
}
